using System.Collections;
using System.Collections.Generic;
using Hotran.SaveSystem;
using UnityEngine;
using Cinemachine;
using UnityEngine.UI;

public class Level : MonoBehaviour, ISavable
{
    private struct SaveData
    {
        public int[] TorchesLit;
        public bool[] Triggers;
    }

    public static event System.Action<float> Win;

    [SerializeField]
    private int _goalTorchLitCount = 3;

    [SerializeField]
    private HandController _player;

    [SerializeField]
    private BodySwing _bodySwing;

    [Header("Level 1 -> 2")]
    [SerializeField]
    private Cable _trigger;
    [SerializeField]
    private FadableSpriteShape _show;

    [Header("Level 2 -> 3")]
    [SerializeField]
    private Cable _trigger2;
    [SerializeField]
    private FadableSpriteShape[] _show2s;

    [Header("Main Level Start")]
    [SerializeField]
    private Cable _trigger3;
    [SerializeField]
    private GameObject _shows;
    [SerializeField]
    private FadableSpriteShape[] _showFades;
    [SerializeField]
    private CinemachineVirtualCamera _followCamera;
    [SerializeField]
    private CinemachineVirtualCamera _overviewCamera;

    [Header("Effects")]
    [SerializeField]
    private ParticleSystem _connectEffect;

    [SerializeField]
    private TargetArrow _targetArrow;
    [SerializeField]
    private GameObject _distText;

    [Header("Goal")]
    [SerializeField]
    private Torch _torchFirst;

    private HashSet<int> _torchesLit = new(2);
    private bool[] _triggers = new bool[5];

    public Text _timeText;
    private float _timer;


    // Start is called before the first frame update
    void Start()
    {
        Torch.Lit += Torch_Lit;
        _player.CableConnected += Player_CableConnected;

        _show.gameObject.SetActive(false);
        foreach (var show in _show2s)
        {
            show.gameObject.SetActive(false);
        }
        _shows.SetActive(false);
        _targetArrow.Target = _torchFirst.transform;
        _targetArrow.gameObject.SetActive(false);
        _distText.SetActive(false);
    }

    private void Update()
    {
        _timer += Time.deltaTime;
        _timeText.text = $"{_timer.ToString("0.0")}s";
    }

    public object Save()
    {
        //bool[] torchesLit = new bool[_torches.Length];
        //for (int i = 0; i < torchesLit.Length; i++)
        //{
        //    if (_torches[i].IsLit)
        //    {
        //        torchesLit[i] = true;
        //    }
        //}
        int[] torchesLit = new int[_torchesLit.Count];
        _torchesLit.CopyTo(torchesLit);
        return new SaveData()
        {
            TorchesLit = torchesLit,
            Triggers = _triggers
        };
    }

    public void Load(object data)
    {
        SaveData saveData = (SaveData)data;
        _triggers = saveData.Triggers;
        _torchesLit = new HashSet<int>(saveData.TorchesLit);
        //for (int i = 0; i < saveData.TorchesLit.Length; i++)
        //{
        //    if (saveData.TorchesLit[i])
        //    {
        //        _torches[i].SetLit(true);
        //    }
        //}
    }

    private void Torch_Lit(Torch torch)
    {
        int id = torch.GetInstanceID();
        if (!_torchesLit.Contains(id))
        {
            _torchesLit.Add(id);
        }
        //Debug.Log(_torchesLit.Count);
        if (_torchesLit.Count >= _goalTorchLitCount)
        {
            WinGame();
        }

        if (torch == _torchFirst)
        {
            _distText.SetActive(false);
            _targetArrow.gameObject.SetActive(false);
        }
    }

    private void WinGame()
    {
        Debug.Log("过关！");

        _player.enabled = false;
        _bodySwing.enabled = false;

        Win?.Invoke(_timer);
    }

    private void Player_CableConnected(Cable cable1, Cable cable2)
    {
        if (cable1.IsLit && cable2.IsLit)
            return;

        if (cable1.IsConnectedToSource(out _))
        {
            cable2.SetParent(cable1);
            _connectEffect.transform.position = cable2.transform.position;
            _connectEffect.Play();
        }
        else if (cable2.IsConnectedToSource(out _))
        {
            cable1.SetParent(cable2);
            _connectEffect.transform.position = cable1.transform.position;
            _connectEffect.Play();
        }
        else
        {
            return;
        }

        CheckTriggers();
    }

    private void CheckTriggers()
    {
        if (!_triggers[0] && _trigger.IsConnectedToSource(out _))
        {
            _show.gameObject.SetActive(true);
            _show.FadeIn();
            _triggers[0] = true;
        }
        if (!_triggers[1] && _trigger2.IsConnectedToSource(out _))
        {
            foreach (var show in _show2s)
            {
                show.gameObject.SetActive(true);
                show.FadeIn();
            }
            
            _triggers[1] = true;
        }
        if (!_triggers[2] && _trigger3.IsConnectedToSource(out _))
        {
            _shows.SetActive(true);
            foreach (var fade in _showFades)
            {
                fade.FadeIn();
            }
            _triggers[2] = true;
            _targetArrow.gameObject.SetActive(true);
            _distText.SetActive(true);
            StartCoroutine(DOSceneOverview());
        }
    }

    private IEnumerator DOSceneOverview()
    {
        _overviewCamera.gameObject.SetActive(true);
        yield return new WaitForSeconds(3f);
        _overviewCamera.gameObject.SetActive(false);
    }
}
